package com.qiaofang.applet.service.other.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qiaofang.applet.common.base.MongoBaseService;
import com.qiaofang.applet.common.util.RedisKeyUtil;
import com.qiaofang.applet.common.util.RedisUtil;
import com.qiaofang.applet.service.other.domain.ProvinceCity;
import com.qiaofang.applet.service.other.repository.ProvinceCityRepository;
import com.qiaofang.applet.service.other.service.ProvinceCityService;
import com.qiaofang.applet.service.other.service.dto.CityDesDto;
import com.qiaofang.applet.service.property.domain.FirsthandEstate;
import com.qiaofang.applet.service.property.service.dto.DistrictDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: youqing.yang
 * @create: 2020/09/22 17:24
 **/
@Service
public class ProvinceCityServiceImpl extends MongoBaseService<ProvinceCity, String> implements ProvinceCityService {

    @Autowired
    private ProvinceCityRepository repository;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    private RedisUtil redisUtil;

    public ProvinceCityServiceImpl(MongoRepository<ProvinceCity, String> repository) {
        super(repository);
    }


    @Override
    public List<CityDesDto> getFirstHandCity(String corporationCode) {
        String firstHandCityListKey = RedisKeyUtil.getFirstHandCityListKey(corporationCode);
        Object obj = redisUtil.get(firstHandCityListKey);
        if (obj != null) {
            return transBean2CityList(obj);
        }
        TypedAggregation tagg = TypedAggregation.newAggregation(FirsthandEstate.class, Arrays.asList(
                TypedAggregation.match(Criteria.where("corporationCode").is(corporationCode)),
                TypedAggregation.group("city").first("city").as("city"),
                TypedAggregation.project("city")
        ));
        AggregationResults result = mongoTemplate.aggregate(tagg, FirsthandEstate.class);
        List<FirsthandEstate> resultList = result.getMappedResults();
        //当前城市所有code
        List<String> cityCodes = Optional.ofNullable(resultList).orElseGet(Lists::newArrayList).stream().map(FirsthandEstate::getCity).collect(Collectors.toList());
        Query queryCitys = new Query().addCriteria(Criteria.where("areaCode").in(cityCodes));
        List<CityDesDto> cityDesDtos = new ArrayList<>();
        List<ProvinceCity> provinceCities = mongoTemplate.find(queryCitys, ProvinceCity.class);
        provinceCities.stream().forEach(s -> {
            CityDesDto entity = new CityDesDto();
            entity.setCityName(s.getName());
            entity.setCityCode(s.getAreaCode());
            cityDesDtos.add(entity);
        });
        if (!CollectionUtils.isEmpty(cityDesDtos)) {
            redisUtil.setToDayEnd(firstHandCityListKey, cityDesDtos);
        }
        return cityDesDtos;
    }

    @Override
    public List<CityDesDto> getFirstHandCity(String corporationCode, List<String> cityCodeList) {
        List<CityDesDto> firstHandCity = getFirstHandCity(corporationCode);
        if (!CollectionUtils.isEmpty(cityCodeList)){
            Iterator<CityDesDto> iterator = firstHandCity.iterator();
            while (iterator.hasNext()){
                CityDesDto cityDesDto = iterator.next();
                if (!cityCodeList.contains(cityDesDto.getCityCode())){
                    iterator.remove();
                }
            }
        }
        return firstHandCity;
    }

    private List<CityDesDto> transBean2CityList(Object obj) {
        return JSONObject.parseArray(JSONObject.toJSONString(obj), CityDesDto.class);
    }

    @Override
    public List<DistrictDto> getFirstHandArea(String cityCode) {
        String firstHandAreaListKey = RedisKeyUtil.getFirstHandAreaListKey(cityCode);
        Object obj = redisUtil.get(firstHandAreaListKey);
        if (obj != null) {
            return transBean2AreaList(obj);
        }
        TypedAggregation tagg = TypedAggregation.newAggregation(ProvinceCity.class, Arrays.asList(
                TypedAggregation.match(Criteria.where("parentCode").is(cityCode)),
                TypedAggregation.group("areaCode").first("areaCode").as("areaCode")
                        .first("name").as("name"),
                TypedAggregation.project("areaCode", "name")
        ));
        AggregationResults result = mongoTemplate.aggregate(tagg, ProvinceCity.class);
        List<ProvinceCity> resultList = result.getMappedResults();
        List<DistrictDto> areaDtos = new ArrayList<>();
        resultList.stream().forEach(s -> {
            DistrictDto districtDto = new DistrictDto();
            districtDto.setDistrictName(s.getName());
            districtDto.setDistrictUuid(s.getAreaCode());
            areaDtos.add(districtDto);
        });
        redisUtil.set(firstHandAreaListKey, areaDtos);
        return areaDtos;
    }

    private List<DistrictDto> transBean2AreaList(Object obj) {
        return JSONObject.parseArray(JSONObject.toJSONString(obj), DistrictDto.class);
    }

    @Override
    public Map<String, String> getCityOrAreaName(List<String> areaCode) {
        if (CollectionUtils.isEmpty(areaCode)) {
            return new HashMap<>();
        }
        Query query = new Query().addCriteria(Criteria.where("areaCode").in(areaCode));
        Map<String, String> collect = mongoTemplate.find(query, ProvinceCity.class).stream().distinct().collect(Collectors.toMap(ProvinceCity::getAreaCode, ProvinceCity::getName));
        return Optional.ofNullable(collect).orElseGet(Maps::newHashMap);
    }
}
